package com.yunspace.dropwizard.xml.jersey.jackson.xml; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.lang.annotation.Annotation; import java.util.Arrays; import java.util.List; import java.util.Locale; import javax.validation.ConstraintViolationException; import javax.validation.Valid; import javax.validation.Validation; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedHashMap; import org.hamcrest.CoreMatchers; import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import com.fasterxml.jackson.annotation.JsonIgnoreType; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; import com.yunspace.dropwizard.xml.jackson.JacksonXML; import com.yunspace.dropwizard.xml.jersey.jackson.JacksonXMLMessageBodyProvider; import io.dropwizard.validation.ConstraintViolations; import io.dropwizard.validation.Validated; import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; @SuppressWarnings("unchecked") public class JacksonXMLMessageBodyProviderTest { private static final Annotation[] NONE = new Annotation[0]; private static class Example { @Min(0) @JacksonXmlProperty int id; } interface Partial1 {} interface Partial2 {} private static class PartialExample { @Min(value = 0, groups = Partial1.class) @JacksonXmlProperty int id; @NotNull(groups = Partial2.class) @JacksonXmlProperty String text; } //tests wrapped and unwrapped lists, to verify jackson-dataformat-xml //<a href="https://github.com/FasterXML/jackson-dataformat-xml/issues/58">Issue 58</a> private static class ListExample { @JacksonXmlProperty(localName = "wrappedList") List<String> wrappedList; @JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty() List<String> unwrappedList; static final String sampleXml = "<ListExample>\n" + " <unwrappedList>4</unwrappedList>\n" + " <unwrappedList>5</unwrappedList>\n" + " <unwrappedList>6</unwrappedList>\n" + " <wrappedList>\n" + " <wrappedList>1</wrappedList>\n" + " <wrappedList>2</wrappedList>\n" + " <wrappedList>3</wrappedList>\n" + " </wrappedList>\n" + "</ListExample>\n"; } private static class AttributeExample { @JacksonXmlProperty(isAttribute = true) String version; } @JacksonXmlRootElement(localName = "NamespaceAndText", namespace = "lostInSpace") private static class NamespaceLocalNameExample { @JacksonXmlText @JacksonXmlElementWrapper(localName = "TextValue") String text; } @JsonIgnoreType(false) interface NonIgnorable extends Ignorable { } @JsonIgnoreType interface Ignorable { } private final XmlMapper mapper = JacksonXML.newXMLMapper(); private final JacksonXMLMessageBodyProvider provider = new JacksonXMLMessageBodyProvider(mapper, Validation.buildDefaultValidatorFactory().getValidator()); @Before public void setUp() throws Exception { mapper.enable(INDENT_OUTPUT); Assume.assumeThat(Locale.getDefault().getLanguage(), CoreMatchers.is("en")); } @Test public void readsDeserializableTypes() throws Exception { assertThat(provider.isReadable(Example.class, null, null, null)) .isTrue(); } @Test public void writesSerializableTypes() throws Exception { assertThat(provider.isWriteable(Example.class, null, null, null)) .isTrue(); } @Test public void doesNotWriteIgnoredTypes() throws Exception { assertThat(provider.isWriteable(Ignorable.class, null, null, null)) .isFalse(); } @Test public void writesUnIgnoredTypes() throws Exception { assertThat(provider.isWriteable(NonIgnorable.class, null, null, null)) .isTrue(); } @Test public void doesNotReadIgnoredTypes() throws Exception { assertThat(provider.isReadable(Ignorable.class, null, null, null)) .isFalse(); } @Test public void readsUnIgnoredTypes() throws Exception { assertThat(provider.isReadable(NonIgnorable.class, null, null, null)) .isTrue(); } @Test public void isChunked() throws Exception { assertThat(provider.getSize(null, null, null, null, null)) .isEqualTo(-1); } @Test public void deserializesRequestEntities() throws Exception { final ByteArrayInputStream entity = new ByteArrayInputStream("<Example xmlns=\"\"><id>1</id></Example>".getBytes()); final Class<?> klass = Example.class; final Object obj = provider.readFrom((Class<Object>) klass, Example.class, NONE, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), entity); assertThat(obj) .isInstanceOf(Example.class); assertThat(((Example) obj).id) .isEqualTo(1); } @Test public void deserializesRequestList() throws Exception { final ByteArrayInputStream requestList = new ByteArrayInputStream(( ListExample.sampleXml).getBytes()); final Class<?> klass = ListExample.class; final Object obj = provider.readFrom((Class<Object>) klass, ListExample.class, NONE, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), requestList); assertThat(obj) .isInstanceOf(ListExample.class); assertThat(((ListExample) obj).unwrappedList) .isEqualTo(Arrays.asList("4", "5", "6")); assertThat(((ListExample) obj).wrappedList) .isEqualTo(Arrays.asList("1", "2", "3")); } @Test public void derializeEntityWithAttribute() throws Exception { final ByteArrayInputStream entity = new ByteArrayInputStream( "<AttributeAndTextExample xmlns=\"\" version=\"1.0\"/>".getBytes()); final Class<?> klass = AttributeExample.class; final Object obj = provider.readFrom((Class<Object>) klass, AttributeExample.class, NONE, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), entity); assertThat(obj) .isInstanceOf(AttributeExample.class); assertThat(((AttributeExample) obj).version) .isEqualTo("1.0"); } @Test public void returnsPartialValidatedRequestEntities() throws Exception { final Validated valid = Mockito.mock(Validated.class); Mockito.doReturn(Validated.class).when(valid).annotationType(); Mockito.when(valid.value()).thenReturn(new Class[] {Partial1.class, Partial2.class}); final ByteArrayInputStream entity = new ByteArrayInputStream("<PartialExample xmlns=\"\"><id>1</id><text>hello Cemo</text></PartialExample>".getBytes()); final Class<?> klass = PartialExample.class; final Object obj = provider.readFrom((Class<Object>) klass, PartialExample.class, new Annotation[] {valid}, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), entity); assertThat(obj) .isInstanceOf(PartialExample.class); assertThat(((PartialExample) obj).id) .isEqualTo(1); } @Test public void returnsPartialValidatedByGroupRequestEntities() throws Exception { final Validated valid = Mockito.mock(Validated.class); Mockito.doReturn(Validated.class).when(valid).annotationType(); Mockito.when(valid.value()).thenReturn(new Class[] {Partial1.class}); final ByteArrayInputStream entity = new ByteArrayInputStream("<Example xmlns=\"\"><id>1</id></Example>".getBytes()); final Class<?> klass = PartialExample.class; final Object obj = provider.readFrom((Class<Object>) klass, PartialExample.class, new Annotation[] {valid}, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), entity); assertThat(obj) .isInstanceOf(PartialExample.class); assertThat(((PartialExample) obj).id) .isEqualTo(1); } @Test public void throwsAnInvalidEntityExceptionForPartialValidatedRequestEntities() throws Exception { final Validated valid = Mockito.mock(Validated.class); Mockito.doReturn(Validated.class).when(valid).annotationType(); Mockito.when(valid.value()).thenReturn(new Class[] {Partial1.class, Partial2.class}); final ByteArrayInputStream entity = new ByteArrayInputStream("<Example xmlns=\"\"><id>1</id></Example>".getBytes()); try { final Class<?> klass = PartialExample.class; provider.readFrom((Class<Object>) klass, PartialExample.class, new Annotation[] {valid}, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), entity); failBecauseExceptionWasNotThrown(ConstraintViolationException.class); } catch (ConstraintViolationException e) { assertThat(ConstraintViolations.formatUntyped(e.getConstraintViolations())) .containsOnly("text may not be null"); } } @Test public void returnsValidatedRequestEntities() throws Exception { final Annotation valid = Mockito.mock(Annotation.class); Mockito.doReturn(Valid.class).when(valid).annotationType(); final ByteArrayInputStream entity = new ByteArrayInputStream("<Example xmlns=\"\"><id>1</id></Example>".getBytes()); final Class<?> klass = Example.class; final Object obj = provider.readFrom((Class<Object>) klass, Example.class, new Annotation[] {valid}, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), entity); assertThat(obj) .isInstanceOf(Example.class); assertThat(((Example) obj).id) .isEqualTo(1); } @Test public void throwsAnInvalidEntityExceptionForInvalidRequestEntities() throws Exception { final Annotation valid = Mockito.mock(Annotation.class); Mockito.doReturn(Valid.class).when(valid).annotationType(); final ByteArrayInputStream entity = new ByteArrayInputStream("<Example xmlns=\"\"><id>-1</id></Example>".getBytes()); try { final Class<?> klass = Example.class; provider.readFrom((Class<Object>) klass, Example.class, new Annotation[] {valid}, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), entity); failBecauseExceptionWasNotThrown(ConstraintViolationException.class); } catch (ConstraintViolationException e) { assertThat(ConstraintViolations.formatUntyped(e.getConstraintViolations())) .containsOnly("id must be greater than or equal to 0"); } } @Test public void throwsAJsonProcessingExceptionForMalformedRequestEntities() throws Exception { final ByteArrayInputStream entity = new ByteArrayInputStream("<Example xmlns=\"\"><id>-1d</id></Example>".getBytes()); try { final Class<?> klass = Example.class; provider.readFrom((Class<Object>) klass, Example.class, NONE, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), entity); failBecauseExceptionWasNotThrown(WebApplicationException.class); } catch (JsonProcessingException e) { assertThat(e.getMessage()) .startsWith("Can not construct instance of int from String value"); } } @Test public void serializesResponseEntities() throws Exception { final ByteArrayOutputStream output = new ByteArrayOutputStream(); final Example example = new Example(); example.id = 500; provider.writeTo(example, Example.class, Example.class, NONE, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), output); assertThat(output.toString()) .isEqualTo( "<Example>" + System.lineSeparator() + " <id>500</id>" + System.lineSeparator() + "</Example>" + System.lineSeparator()); } @Test public void serializesResponseList() throws Exception { final ByteArrayOutputStream output = new ByteArrayOutputStream(); final ListExample listExample = new ListExample(); listExample.wrappedList = Arrays.asList("1", "2", "3"); listExample.unwrappedList = Arrays.asList("4", "5", "6"); provider.writeTo(listExample, ListExample.class, ListExample.class, NONE, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), output); assertThat(output.toString()) .isEqualTo(ListExample.sampleXml); } @Test public void serializeResponseWithAttribute() throws Exception { final ByteArrayOutputStream output = new ByteArrayOutputStream(); final AttributeExample attributeAndTextExample = new AttributeExample(); attributeAndTextExample.version = "2.0"; provider.writeTo(attributeAndTextExample, AttributeExample.class, AttributeExample.class, NONE, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), output); assertThat(output.toString()) .isEqualTo("<AttributeExample version=\"2.0\"/>" + System.lineSeparator()); } @Test public void serializeResponseNamespace() throws Exception { final ByteArrayOutputStream output = new ByteArrayOutputStream(); final NamespaceLocalNameExample namespaceLocalNameExample = new NamespaceLocalNameExample(); namespaceLocalNameExample.text = "hello world"; provider.writeTo(namespaceLocalNameExample, NamespaceLocalNameExample.class, NamespaceLocalNameExample.class, NONE, MediaType.APPLICATION_XML_TYPE, new MultivaluedHashMap<>(), output); assertThat(output.toString()) .isEqualTo("<NamespaceAndText xmlns=\"lostInSpace\">hello world</NamespaceAndText>" + System.lineSeparator()); } }